package service

import (
	"context"
	"encoding/json"
	"github.com/gin-gonic/gin"
	"gochat/common"
	"gochat/common/enums"
	"gochat/domain/request"
	"gochat/domain/response/result"
	"gochat/models"
	"gochat/utils"
	"log"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"time"
)

type LoginServiceImpl struct {
}

func (receiver *LoginServiceImpl) Login(c *gin.Context, req request.LoginRequest) {
	var user models.UserBasic
	db := common.DB
	rdb := common.RDB
	tx := db.First(&user, "user_name = ?", req.UserName)
	if tx.RowsAffected == 0 {
		tx = db.First(&user, "email = ?", req.UserName)
		if tx.RowsAffected == 0 {
			tx = db.First(&user, "phone = ?", req.UserName)
			if tx.RowsAffected == 0 {
				result.Fail(c, 400, "用户不存在")
				return
			}
		}
	}
	if !utils.Match(req.Password, user.Password) {
		result.Fail(c, 400, "密码错误")
		return
	}
	//判断是否登录
	if rdb.Get(context.Background(), enums.USER_LOGIN_PREV+strconv.Itoa(int(user.ID))).Val() != "" {
		rdb.Del(context.Background(), enums.TOKEN_SECRET+strconv.Itoa(int(user.ID)))
	}
	//创建token并返回
	token, err := utils.GenerateToken(strconv.Itoa(int(user.ID)))
	if err != nil {
		log.Println(err)
		result.Fail(c, 500, "服务器未知异常")
		return
	}
	//存储登录信息
	user.ClientIP = c.ClientIP()
	user.LoginTime = time.Now()
	err = db.Save(user).Error
	if err != nil {
		log.Println(err)
		result.Fail(c, 500, "服务器未知异常")
		return
	}
	rdb.Set(context.Background(), enums.USER_LOGIN_PREV+strconv.Itoa(int(user.ID)), user, time.Hour*24*7)

	result.Ok(c, gin.H{"token": token})
}

func (receiver *LoginServiceImpl) Logout(c *gin.Context) {
	uid, _ := c.Get("uid")
	rst := common.RDB.Del(context.Background(), enums.USER_LOGIN_PREV+uid.(string))
	if rst.Err() != nil {
		result.Fail(c, 500, "服务器未知异常")
		return
	}
	result.Ok(c, "退出成功")
}

func (receiver *LoginServiceImpl) GithubOAuth(c *gin.Context, code string) {
	var rdb = common.RDB
	var db = common.DB
	proxyUrl, _ := url.Parse("http://127.0.0.1:7890") // 本地代理
	transport := &http.Transport{
		Proxy: http.ProxyURL(proxyUrl),
	}
	client := &http.Client{Transport: transport}
	// 1. 用 code 换 access_token
	form := url.Values{
		"client_id":     {"Ov23lilR0aYq48IbbaEt"},
		"client_secret": {"33924eb8f2e6ff71098211cafb59aac9f2c4898d"},
		"code":          {code},
	}

	req, err := http.NewRequest("POST", "https://github.com/login/oauth/access_token", strings.NewReader(form.Encode()))
	if err != nil {
		log.Println("创建请求失败:", err)
		result.Fail(c, 500, "创建请求失败")
		return
	}
	req.Header.Set("Accept", "application/json")
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")

	resp, err := client.Do(req)
	if err != nil {
		log.Println("访问 GitHub 授权接口失败:", err)
		result.Fail(c, 500, "网络连接失败")
		return
	}
	defer resp.Body.Close()

	// 解析 access_token 响应
	var tokenData struct {
		AccessToken string `json:"access_token"`
		TokenType   string `json:"token_type"`
		Scope       string `json:"scope"`
	}
	if err := json.NewDecoder(resp.Body).Decode(&tokenData); err != nil {
		log.Println("解析 access_token 失败:", err)
		result.Fail(c, 500, "授权失败")
		return
	}
	if tokenData.AccessToken == "" {
		log.Println("access_token 为空")
		result.Fail(c, 401, "授权失败")
		return
	}

	// 2. 用 access_token 获取用户信息
	rst, err := http.NewRequest("GET", "https://api.github.com/user", nil)
	if err != nil {
		log.Println("创建用户信息请求失败:", err)
		result.Fail(c, 500, "获取用户信息失败")
		return
	}
	rst.Header.Set("Authorization", "token "+tokenData.AccessToken)
	rst.Header.Set("Accept", "application/json")

	respRst, err := client.Do(rst)
	if err != nil {
		log.Println("请求用户信息失败:", err)
		result.Fail(c, 500, "获取用户信息失败")
		return
	}
	defer respRst.Body.Close()

	var userInfo struct {
		ID        int64  `json:"id"`
		UserName  string `json:"login"`
		NickName  string `json:"name"`
		AvatarURL string `json:"avatar_url"`
		Email     string `json:"email"`
	}
	if err := json.NewDecoder(respRst.Body).Decode(&userInfo); err != nil {
		log.Println("解析用户信息失败:", err)
		result.Fail(c, 500, "解析用户信息失败")
		return
	}
	var user = models.UserBasic{
		UserName:  userInfo.UserName,
		NickName:  userInfo.NickName,
		Email:     userInfo.Email,
		Header:    userInfo.AvatarURL,
		GitHubID:  int(userInfo.ID),
		ClientIP:  c.ClientIP(),
		LoginTime: time.Now(),
	}
	//判断用户是否存在
	if rst := db.First(&user, "github_id = ?", user.GitHubID); rst.RowsAffected == 0 {
		//	不存在则创建
		if err := user.Create(db); err != nil {
			log.Println("创建用户失败:", err)
			result.Fail(c, 500, "创建用户失败")
			return
		}
	} else {
		//	TODO 存在则更新
	}
	//判断是否登录
	if rdb.Get(context.Background(), enums.USER_LOGIN_PREV+strconv.Itoa(int(user.ID))).Val() != "" {
		rdb.Del(context.Background(), enums.TOKEN_SECRET+strconv.Itoa(int(user.ID)))
	}
	//创建token并返回
	token, err := utils.GenerateToken(strconv.Itoa(int(user.ID)))
	if err != nil {
		log.Println(err)
		result.Fail(c, 500, "服务器未知异常")
		return
	}
	rdb.Set(context.Background(), enums.USER_LOGIN_PREV+strconv.Itoa(int(user.ID)), user, time.Hour*24*7)
	result.Ok(c, gin.H{"token": token})
}
